/*
 * Copyright (c) 2010, Katholieke Universiteit Leuven
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of the Katholieke Universiteit Leuven nor the names of
 *       its contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * @addtogroup introspection
 * @{
 */
/**
 * @file 
 * Implementation file for the local introspection functionality
 * @author 
 * Wouter Horré <wouter.horre@cs.kuleuven.be>
 */

#include <string.h>

#include "components/components.h"
#include "components/components_private.h"
#include "events/events_private.h"

#include "introspection_local.h"

#ifdef LOOCI_INTRO_DEBUG
#include <stdio.h>
#ifdef CONTIKI_TARGET_AVR_RAVEN
#include <avr/pgmspace.h>
#define PRINTF(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#else
#define PRINTF printf
#endif // CONTIKI_TARGET_AVR_RAVEN
#else
#define PRINTF(...)
#endif

bool looci_intro_getcomponentids_by_type(char * ctype, u8_t * buffer, u8_t * size) {
  struct component * c = components_get_first();
  u8_t nb = 0;
  for(nb=0; nb < *size && c != NULL; c = c->next) {
    if(strcmp(COMPONENT_NAME(c), ctype)==0) {
      buffer[nb] = c->id;
      ++nb;
    }
  }
  *size = nb;
  if(c == NULL) { // we got to the end :-)
    return true;
  } else { // we didn't get to the end :-(
    return false;
  }
}

bool looci_intro_getcomponentids(u8_t * buffer, u8_t * size) {
  struct component * c = components_get_first();
  u8_t nb = 0;
  for(nb=0; nb < *size && c != NULL; ++nb, c = c->next) {
    buffer[nb] = c->id;
  }
  *size = nb;
  if(c == NULL) { // we got to the end :-)
    return true;
  } else { // we didn't get to the end :-(
    return false;
  }
}

bool looci_intro_getcomponenttype(u8_t cid, char * type, u8_t maxsize) {
  struct component * c = components_get(cid);
  if(c!=NULL) {
    strncpy(type, COMPONENT_NAME(c), maxsize);
    size_t len = strlen(COMPONENT_NAME(c)) + 1; // +1 -> terminating null character
    if(len > maxsize) { // the name is too long to fit in the type buffer
      type[maxsize - 1] = 0; // make sure the string is null terminated
      return false;
    } else {
      return true;
    }
  } else {
    return false;
  }
}

u8_t looci_intro_getstate(u8_t cid) {
  struct component * c = components_get(cid);
  if(c!=NULL) {
    return c->state;
  } else {
    return COMPONENT_STATE_NONE;
  }
}

static bool getintorrec(u8_t intorrec, u8_t cid, looci_eventtype_t * buffer, u8_t * size) {
  struct component * c = components_get(cid);
  if(c!=NULL) {
    looci_eventtype_t * input = NULL;
    u8_t nb = 0;
    if(intorrec == 1) input = c->interfaces;
    else if(intorrec == 2) input = c->receptacles;
    for(nb=0; nb < *size && input[nb] > 0; ++nb) {
      buffer[nb] = input[nb];
    }
    *size = nb;
    if(input[nb] == 0) { // we got to the end of the input \o/
      return true;
    } else { // we didn't get to the end of the input -> return false (*size is > 0)
      return false;
    }
  } else {
    // other error, set *size to 0 and return false.
    *size = 0;
    return false;
  }
}

bool looci_intro_getinterfaces(u8_t cid, looci_eventtype_t * buffer, u8_t * size) {
  return getintorrec(1, cid, buffer, size);
}

bool looci_intro_getreceptacles(u8_t cid, looci_eventtype_t * buffer, u8_t * size) {
  return getintorrec(2, cid, buffer, size);
}

static bool check_interface(looci_eventtype_t eventtype, u8_t cid) {
  struct component * c = components_get(cid);
  if(c == NULL) return false;
  u8_t i;
  for(i=0; c->interfaces[i] != 0; ++i) {
    if(c->interfaces[i] == eventtype) {
      return true;
    }
  }
  return false;
}

bool looci_intro_getoutgoingremotewires(looci_eventtype_t eventtype, u8_t cid, peer_id_t * buffer, u8_t * size) {
  if(check_interface(eventtype, cid) == false) {
    *size = 0;
    return false;
  }
  return events_getremotewires_to(eventtype, cid, buffer, size);
}

bool looci_intro_getincomingremotewires(looci_eventtype_t eventtype, u8_t cid, struct wire_from * buffer, u8_t * size) {
  PRINTF("[LooCI intro] Get incoming remote wires called with *size: %u\r\n", *size);
  struct component * c = components_get(cid);
  if(c == NULL) {
    PRINTF("[LooCI intro] Didn't find the component to get the incoming wires for\r\n");
    *size = 0;
    return false;
  }
  return events_getremotewires_from(eventtype, cid, buffer, size);
}

bool looci_intro_getlocalwires(looci_eventtype_t eventtype, u8_t cid, u8_t * buffer, u8_t * size) {
  if(check_interface(eventtype, cid) == false) {
    *size = 0;
    return false;
  }
  return events_getlocalwires(eventtype, cid, buffer, size);
}
/** @} */
